// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraCameraMode.h"

#include "Components/CapsuleComponent.h"
#include "Engine/Canvas.h"
#include "GameFramework/Character.h"
#include "LyraCameraComponent.h"
#include "LyraPlayerCameraManager.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraCameraMode)


//////////////////////////////////////////////////////////////////////////
// FLyraCameraModeView
//////////////////////////////////////////////////////////////////////////
FLyraCameraModeView::FLyraCameraModeView()
	: Location(ForceInit) // 强制初始化位置
	, Rotation(ForceInit) // 强制初始化旋转
	, ControlRotation(ForceInit) // 强制初始化控制旋转
	, FieldOfView(LYRA_CAMERA_DEFAULT_FOV) // 使用默认视野初始化
{
}

void FLyraCameraModeView::Blend(const FLyraCameraModeView& Other, float OtherWeight)
{
	if (OtherWeight <= 0.0f) // 如果其他权重小于等于0
	{
		return; // 不进行混合
	}
	else if (OtherWeight >= 1.0f) // 如果其他权重大于等于1
	{
		*this = Other; // 直接赋值
		return;
	}

	Location = FMath::Lerp(Location, Other.Location, OtherWeight); // 线性插值位置

	const FRotator DeltaRotation = (Other.Rotation - Rotation).GetNormalized(); // 计算旋转差值并归一化
	Rotation = Rotation + (OtherWeight * DeltaRotation); // 加权旋转

	const FRotator DeltaControlRotation = (Other.ControlRotation - ControlRotation).GetNormalized(); // 计算控制旋转差值并归一化
	ControlRotation = ControlRotation + (OtherWeight * DeltaControlRotation); // 加权控制旋转

	FieldOfView = FMath::Lerp(FieldOfView, Other.FieldOfView, OtherWeight); // 线性插值视野
}


//////////////////////////////////////////////////////////////////////////
// ULyraCameraMode
//////////////////////////////////////////////////////////////////////////
ULyraCameraMode::ULyraCameraMode()
{
	FieldOfView = LYRA_CAMERA_DEFAULT_FOV; // 设置默认视野
	ViewPitchMin = LYRA_CAMERA_DEFAULT_PITCH_MIN; // 设置默认最小俯仰角
	ViewPitchMax = LYRA_CAMERA_DEFAULT_PITCH_MAX; // 设置默认最大俯仰角

	BlendTime = 0.5f; // 设置混合时间
	BlendFunction = ELyraCameraModeBlendFunction::EaseOut; // 设置混合函数为缓出
	BlendExponent = 4.0f; // 设置混合指数
	BlendAlpha = 1.0f; // 设置混合Alpha
	BlendWeight = 1.0f; // 设置混合权重
}

ULyraCameraComponent* ULyraCameraMode::GetLyraCameraComponent() const
{
	return CastChecked<ULyraCameraComponent>(GetOuter()); // 转换并检查外部对象为Lyra相机组件
}

UWorld* ULyraCameraMode::GetWorld() const
{
	return HasAnyFlags(RF_ClassDefaultObject) ? nullptr : GetOuter()->GetWorld(); // 如果是类默认对象则返回nullptr，否则返回外部对象的世界
}

AActor* ULyraCameraMode::GetTargetActor() const
{
	const ULyraCameraComponent* LyraCameraComponent = GetLyraCameraComponent(); // 获取Lyra相机组件

	return LyraCameraComponent->GetTargetActor(); // 返回目标Actor
}

FVector ULyraCameraMode::GetPivotLocation() const
{
	const AActor* TargetActor = GetTargetActor(); // 获取目标Actor
	check(TargetActor); // 检查目标Actor有效

	if (const APawn* TargetPawn = Cast<APawn>(TargetActor)) // 如果目标Actor是Pawn
	{
		// 为角色调整高度以考虑下蹲。
		if (const ACharacter* TargetCharacter = Cast<ACharacter>(TargetPawn)) // 如果目标Pawn是角色
		{
			const ACharacter* TargetCharacterCDO = TargetCharacter->GetClass()->GetDefaultObject<ACharacter>(); // 获取角色的类默认对象
			check(TargetCharacterCDO); // 检查类默认对象有效

			const UCapsuleComponent* CapsuleComp = TargetCharacter->GetCapsuleComponent(); // 获取胶囊体组件
			check(CapsuleComp); // 检查胶囊体组件有效

			const UCapsuleComponent* CapsuleCompCDO = TargetCharacterCDO->GetCapsuleComponent(); // 获取类默认对象的胶囊体组件
			check(CapsuleCompCDO); // 检查类默认胶囊体组件有效

			const float DefaultHalfHeight = CapsuleCompCDO->GetUnscaledCapsuleHalfHeight(); // 获取默认未缩放胶囊体半高
			const float ActualHalfHeight = CapsuleComp->GetUnscaledCapsuleHalfHeight(); // 获取实际未缩放胶囊体半高
			const float HeightAdjustment = (DefaultHalfHeight - ActualHalfHeight) + TargetCharacterCDO->BaseEyeHeight; // 计算高度调整值

			return TargetCharacter->GetActorLocation() + (FVector::UpVector * HeightAdjustment); // 返回调整后的位置
		}

		return TargetPawn->GetPawnViewLocation(); // 返回Pawn的视角位置
	}

	return TargetActor->GetActorLocation(); // 返回Actor的位置
}

FRotator ULyraCameraMode::GetPivotRotation() const
{
	const AActor* TargetActor = GetTargetActor(); // 获取目标Actor
	check(TargetActor); // 检查目标Actor有效

	if (const APawn* TargetPawn = Cast<APawn>(TargetActor)) // 如果目标Actor是Pawn
	{
		return TargetPawn->GetViewRotation(); // 返回Pawn的视角旋转
	}

	return TargetActor->GetActorRotation(); // 返回Actor的旋转
}

void ULyraCameraMode::UpdateCameraMode(float DeltaTime)
{
	UpdateView(DeltaTime); // 更新视图
	UpdateBlending(DeltaTime); // 更新混合
}

void ULyraCameraMode::UpdateView(float DeltaTime)
{
	FVector PivotLocation = GetPivotLocation(); // 获取枢轴位置
	FRotator PivotRotation = GetPivotRotation(); // 获取枢轴旋转

	PivotRotation.Pitch = FMath::ClampAngle(PivotRotation.Pitch, ViewPitchMin, ViewPitchMax); // 限制俯仰角在最小和最大值之间

	View.Location = PivotLocation; // 设置视图位置
	View.Rotation = PivotRotation; // 设置视图旋转
	View.ControlRotation = View.Rotation; // 设置控制旋转
	View.FieldOfView = FieldOfView; // 设置视图视野
}

void ULyraCameraMode::SetBlendWeight(float Weight)
{
	BlendWeight = FMath::Clamp(Weight, 0.0f, 1.0f); // 限制混合权重在0到1之间

	// 由于我们直接设置混合权重，我们需要计算混合Alpha以考虑混合函数。
	const float InvExponent = (BlendExponent > 0.0f) ? (1.0f / BlendExponent) : 1.0f; // 计算逆指数

	switch (BlendFunction) // 根据混合函数类型
	{
	case ELyraCameraModeBlendFunction::Linear: // 线性混合
		BlendAlpha = BlendWeight; // Alpha等于权重
		break;

	case ELyraCameraModeBlendFunction::EaseIn: // 缓入混合
		BlendAlpha = FMath::InterpEaseIn(0.0f, 1.0f, BlendWeight, InvExponent); // 缓入插值
		break;

	case ELyraCameraModeBlendFunction::EaseOut: // 缓出混合
		BlendAlpha = FMath::InterpEaseOut(0.0f, 1.0f, BlendWeight, InvExponent); // 缓出插值
		break;

	case ELyraCameraModeBlendFunction::EaseInOut: // 缓入缓出混合
		BlendAlpha = FMath::InterpEaseInOut(0.0f, 1.0f, BlendWeight, InvExponent); // 缓入缓出插值
		break;

	default:
		checkf(false, TEXT("SetBlendWeight: Invalid BlendFunction [%d]\n"), (uint8)BlendFunction); // 检查混合函数无效
		break;
	}
}

void ULyraCameraMode::UpdateBlending(float DeltaTime)
{
	if (BlendTime > 0.0f) // 如果混合时间大于0
	{
		BlendAlpha += (DeltaTime / BlendTime); // 增加混合Alpha
		BlendAlpha = FMath::Min(BlendAlpha, 1.0f); // 限制混合Alpha不超过1
	}
	else
	{
		BlendAlpha = 1.0f; // 否则直接设置为1
	}

	const float Exponent = (BlendExponent > 0.0f) ? BlendExponent : 1.0f; // 计算指数

	switch (BlendFunction) // 根据混合函数类型
	{
	case ELyraCameraModeBlendFunction::Linear: // 线性混合
		BlendWeight = BlendAlpha; // 权重等于Alpha
		break;

	case ELyraCameraModeBlendFunction::EaseIn: // 缓入混合
		BlendWeight = FMath::InterpEaseIn(0.0f, 1.0f, BlendAlpha, Exponent); // 缓入插值
		break;

	case ELyraCameraModeBlendFunction::EaseOut: // 缓出混合
		BlendWeight = FMath::InterpEaseOut(0.0f, 1.0f, BlendAlpha, Exponent); // 缓出插值
		break;

	case ELyraCameraModeBlendFunction::EaseInOut: // 缓入缓出混合
		BlendWeight = FMath::InterpEaseInOut(0.0f, 1.0f, BlendAlpha, Exponent); // 缓入缓出插值
		break;

	default:
		checkf(false, TEXT("UpdateBlending: Invalid BlendFunction [%d]\n"), (uint8)BlendFunction); // 检查混合函数无效
		break;
	}
}

void ULyraCameraMode::DrawDebug(UCanvas* Canvas) const
{
	check(Canvas); // 检查Canvas有效

	FDisplayDebugManager& DisplayDebugManager = Canvas->DisplayDebugManager; // 获取调试显示管理器

	DisplayDebugManager.SetDrawColor(FColor::White); // 设置绘制颜色为白色
	DisplayDebugManager.DrawString(FString::Printf(TEXT("      LyraCameraMode: %s (%f)"), *GetName(), BlendWeight)); // 绘制相机模式名称和混合权重
}


//////////////////////////////////////////////////////////////////////////
// ULyraCameraModeStack
//////////////////////////////////////////////////////////////////////////
ULyraCameraModeStack::ULyraCameraModeStack()
{
	bIsActive = true; // 默认激活堆栈
}

void ULyraCameraModeStack::ActivateStack()
{
	if (!bIsActive) // 如果堆栈未激活
	{
		bIsActive = true; // 激活堆栈

		// 通知相机模式它们正在被激活。
		for (ULyraCameraMode* CameraMode : CameraModeStack) // 遍历相机模式堆栈
		{
			check(CameraMode); // 检查相机模式有效
			CameraMode->OnActivation(); // 调用激活函数
		}
	}
}

void ULyraCameraModeStack::DeactivateStack()
{
	if (bIsActive) // 如果堆栈已激活
	{
		bIsActive = false; // 停用堆栈

		// 通知相机模式它们正在被停用。
		for (ULyraCameraMode* CameraMode : CameraModeStack) // 遍历相机模式堆栈
		{
			check(CameraMode); // 检查相机模式有效
			CameraMode->OnDeactivation(); // 调用停用函数
		}
	}
}

void ULyraCameraModeStack::PushCameraMode(TSubclassOf<ULyraCameraMode> CameraModeClass)
{
	if (!CameraModeClass) // 如果相机模式类无效
	{
		return; // 直接返回
	}

	ULyraCameraMode* CameraMode = GetCameraModeInstance(CameraModeClass); // 获取相机模式实例
	check(CameraMode); // 检查相机模式有效

	int32 StackSize = CameraModeStack.Num(); // 获取堆栈大小

	if ((StackSize > 0) && (CameraModeStack[0] == CameraMode)) // 如果堆栈不为空且顶部已经是该相机模式
	{
		// 已经是堆栈顶部。
		return; // 直接返回
	}

	// 查看它是否已经在堆栈中并移除它。
	// 找出它对堆栈的贡献程度。
	int32 ExistingStackIndex = INDEX_NONE; // 现有堆栈索引
	float ExistingStackContribution = 1.0f; // 现有堆栈贡献

	for (int32 StackIndex = 0; StackIndex < StackSize; ++StackIndex) // 遍历堆栈
	{
		if (CameraModeStack[StackIndex] == CameraMode) // 如果找到相同相机模式
		{
			ExistingStackIndex = StackIndex; // 记录索引
			ExistingStackContribution *= CameraMode->GetBlendWeight(); // 乘以混合权重
			break; // 跳出循环
		}
		else
		{
			ExistingStackContribution *= (1.0f - CameraModeStack[StackIndex]->GetBlendWeight()); // 乘以(1-混合权重)
		}
	}

	if (ExistingStackIndex != INDEX_NONE) // 如果找到现有索引
	{
		CameraModeStack.RemoveAt(ExistingStackIndex); // 从堆栈中移除
		StackSize--; // 堆栈大小减1
	}
	else
	{
		ExistingStackContribution = 0.0f; // 否则贡献为0
	}

	// 决定使用什么初始权重开始。
	const bool bShouldBlend = ((CameraMode->GetBlendTime() > 0.0f) && (StackSize > 0)); // 判断是否应该混合
	const float BlendWeight = (bShouldBlend ? ExistingStackContribution : 1.0f); // 计算混合权重

	CameraMode->SetBlendWeight(BlendWeight); // 设置相机模式的混合权重

	// 将新条目添加到堆栈顶部。
	CameraModeStack.Insert(CameraMode, 0); // 在索引0处插入

	// 确保堆栈底部始终加权100%。
	CameraModeStack.Last()->SetBlendWeight(1.0f); // 设置最后一个元素的混合权重为1

	// 让相机模式知道它被添加到堆栈中。
	if (ExistingStackIndex == INDEX_NONE) // 如果是新添加
	{
		CameraMode->OnActivation(); // 调用激活函数
	}
}

bool ULyraCameraModeStack::EvaluateStack(float DeltaTime, FLyraCameraModeView& OutCameraModeView)
{
	if (!bIsActive) // 如果堆栈未激活
	{
		return false; // 返回false
	}

	UpdateStack(DeltaTime); // 更新堆栈
	BlendStack(OutCameraModeView); // 混合堆栈

	return true; // 返回true
}

ULyraCameraMode* ULyraCameraModeStack::GetCameraModeInstance(TSubclassOf<ULyraCameraMode> CameraModeClass)
{
	check(CameraModeClass); // 检查相机模式类有效

	// 首先查看是否已经创建了一个。
	for (ULyraCameraMode* CameraMode : CameraModeInstances) // 遍历相机模式实例
	{
		if ((CameraMode != nullptr) && (CameraMode->GetClass() == CameraModeClass)) // 如果找到相同类的实例
		{
			return CameraMode; // 返回该实例
		}
	}

	// 未找到，所以需要创建它。
	ULyraCameraMode* NewCameraMode = NewObject<ULyraCameraMode>(GetOuter(), CameraModeClass, NAME_None, RF_NoFlags); // 创建新相机模式对象
	check(NewCameraMode); // 检查新相机模式有效

	CameraModeInstances.Add(NewCameraMode); // 添加到实例数组

	return NewCameraMode; // 返回新实例
}

void ULyraCameraModeStack::UpdateStack(float DeltaTime)
{
	const int32 StackSize = CameraModeStack.Num(); // 获取堆栈大小
	if (StackSize <= 0) // 如果堆栈为空
	{
		return; // 直接返回
	}

	int32 RemoveCount = 0; // 移除计数
	int32 RemoveIndex = INDEX_NONE; // 移除索引

	for (int32 StackIndex = 0; StackIndex < StackSize; ++StackIndex) // 遍历堆栈
	{
		ULyraCameraMode* CameraMode = CameraModeStack[StackIndex]; // 获取相机模式
		check(CameraMode); // 检查相机模式有效

		CameraMode->UpdateCameraMode(DeltaTime); // 更新相机模式

		if (CameraMode->GetBlendWeight() >= 1.0f) // 如果混合权重大于等于1
		{
			// 此模式下面的所有内容现在都不相关，可以移除。
			RemoveIndex = (StackIndex + 1); // 设置移除索引
			RemoveCount = (StackSize - RemoveIndex); // 计算移除数量
			break; // 跳出循环
		}
	}

	if (RemoveCount > 0) // 如果有需要移除的元素
	{
		// 让相机模式知道它们正从堆栈中移除。
		for (int32 StackIndex = RemoveIndex; StackIndex < StackSize; ++StackIndex) // 遍历需要移除的范围
		{
			ULyraCameraMode* CameraMode = CameraModeStack[StackIndex]; // 获取相机模式
			check(CameraMode); // 检查相机模式有效

			CameraMode->OnDeactivation(); // 调用停用函数
		}

		CameraModeStack.RemoveAt(RemoveIndex, RemoveCount); // 从堆栈中移除
	}
}

void ULyraCameraModeStack::BlendStack(FLyraCameraModeView& OutCameraModeView) const
{
	const int32 StackSize = CameraModeStack.Num(); // 获取堆栈大小
	if (StackSize <= 0) // 如果堆栈为空
	{
		return; // 直接返回
	}

	// 从底部开始向上混合堆栈
	const ULyraCameraMode* CameraMode = CameraModeStack[StackSize - 1]; // 获取底部相机模式
	check(CameraMode); // 检查相机模式有效

	OutCameraModeView = CameraMode->GetCameraModeView(); // 设置输出视图

	for (int32 StackIndex = (StackSize - 2); StackIndex >= 0; --StackIndex) // 从倒数第二个向上遍历
	{
		CameraMode = CameraModeStack[StackIndex]; // 获取相机模式
		check(CameraMode); // 检查相机模式有效

		OutCameraModeView.Blend(CameraMode->GetCameraModeView(), CameraMode->GetBlendWeight()); // 混合视图
	}
}

void ULyraCameraModeStack::DrawDebug(UCanvas* Canvas) const
{
	check(Canvas); // 检查Canvas有效

	FDisplayDebugManager& DisplayDebugManager = Canvas->DisplayDebugManager; // 获取调试显示管理器

	DisplayDebugManager.SetDrawColor(FColor::Green); // 设置绘制颜色为绿色
	DisplayDebugManager.DrawString(FString(TEXT("   --- Camera Modes (Begin) ---"))); // 绘制开始标记

	for (const ULyraCameraMode* CameraMode : CameraModeStack) // 遍历相机模式堆栈
	{
		check(CameraMode); // 检查相机模式有效
		CameraMode->DrawDebug(Canvas); // 绘制相机模式调试信息
	}

	DisplayDebugManager.SetDrawColor(FColor::Green); // 设置绘制颜色为绿色
	DisplayDebugManager.DrawString(FString::Printf(TEXT("   --- Camera Modes (End) ---"))); // 绘制结束标记
}

void ULyraCameraModeStack::GetBlendInfo(float& OutWeightOfTopLayer, FGameplayTag& OutTagOfTopLayer) const
{
	if (CameraModeStack.Num() == 0) // 如果堆栈为空
	{
		OutWeightOfTopLayer = 1.0f; // 设置顶层权重为1
		OutTagOfTopLayer = FGameplayTag(); // 设置顶层标签为空
		return;
	}
	else
	{
		ULyraCameraMode* TopEntry = CameraModeStack.Last(); // 获取顶层条目
		check(TopEntry); // 检查顶层条目有效
		OutWeightOfTopLayer = TopEntry->GetBlendWeight(); // 设置顶层权重
		OutTagOfTopLayer = TopEntry->GetCameraTypeTag(); // 设置顶层标签
	}
}